"""
    1、pycharm安装selenium库：
        pip install selenium
    2、pycharm检查是否安装成功
        pip show selenium
    3、使用selenium时需要下载对应浏览器驱动，下载后需要放置在path环境变量中
    4、谷歌驱动下载：
        下载教程网址：https://blog.csdn.net/weixin_42126918/article/details/120892243?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-1-120892243-blog-106468208.235^v38^pc_relevant_anti_t3_base&spm=1001.2101.3001.4242.2&utm_relevant_index=4
        下载网址：https://registry.npmmirror.com/binary.html?path=chromedriver/
        最新下载网址：https://googlechromelabs.github.io/chrome-for-testing/#stable
    5、驱动下载成功后，放置在谷歌浏览器所在目录下，以及python所在目录下
    6、配置环境变量：
        电脑-高级设置-环境变量-找到path-双击-输入谷歌浏览器所在路径
    7、selenium版本过高，导致浏览器自动关闭
    8、使用语法：
        # 引入相关模块/包
        import selenium   # 导入整个selenium库
        from selenium import webdriver    # 引入webdriver模块
        from selenium.webdriver.common.by import By    # 元素选择by模块

        # 浏览器驱动初始化
        driver = webdriver.Chrome()            # 初始化谷歌浏览器驱动，不同浏览器调用不同方法初始化
        driver.get("需要打开的网页路径")          #  打开网页

        # 查找元素
        element = driver.find_element()          # 查找单个元素
        element = driver.find_elements()          # 查找多个元素

        # 定位元素
        element = driver.find_element(By.ID,'id属性值')        # 通过css中的id属性定位元素
        elements = driver.find_element(By.CLASS_NAME,‘class属性值')      # 通过css中的class属性定位元素
        elements = driver.find_element(By.TAG_NAME,'元素标签名 div span等')          # 通过css中的标签定位元素
        element = driver.find_element(By.CSS_SELECTOR,'选择器表达式')         # 通过css的元素选择器定位元素
        element = driver.find_element(By.,'选择器表达式')         # 通过xpath定位元素

        # 获取元素信息
        context = element.text      # 获取元素展示在页面上的文本内容

        # 获取元素的属性对应的信息
        attribute_value = element.get_attribute("属性名")     # 获取元素中属性名对应的value值
        context = element.get_attribute("innerText")        # 获取元素中innerText属性的值
        context = element.get_attribute("textContent")      # 获取元素中textContent属性的值
        html = element.get_attribute("outerHTML")          # 获取元素中outerHTML属性的值

        # 操作元素
        element.send_keys("内容")     # 输入内容
        element.clear()        # 清空内容
        element.click()        # 点击元素

        # 最后关闭浏览器
        driver.quit()

    9、元素定位方法--css选择器
        id选择语法：  #id值
        class选择语法：  .class值
        其他属性选择语法：   [属性名]
        其他属性选择语法：   [属性名 = '属性值']
        子级元素选择语法：   父元素 > 子级元素
        后台元素选择语法：   父元素 后代元素
        相邻兄弟元素2选择语法：      元素1 + 元素2
        相邻兄弟所有元素选择语法：    元素1 ~ 元素2
        按次序查找子节点，指定选择父节点下的第num个子节点元素：          :nth-child(num)
        按次序查找倒数字节点，指定选择父元素下的倒数第num个子节点元素：    :nth-last-child(num)
        按次序查找父节点下类型为xx的第num个子节点：            :nth-of-type(num)
        按次序查找父节点下类型为xx的倒数第num个子节点：         :nth-last-of-type(num)
        按次序查找父节点下的偶数子节点：         :nth-child(even)
        按次序查找父节点下的奇数子节点：         :nth-child(odd)
        按次序查找父节点下的类型为xx的偶数子节点： :nth-of-type(even)
        按次序查找父节点下的类型为xx的奇数子节点： :nth-of-type(odd)

    10、元素定位方法--xpath




"""
import time
# import
# 导入第三方库 selenium
from selenium import webdriver
from selenium.webdriver.common.by import By

# webdriver对象 查找元素时是查找整个网页中满足的元素
# webElement对象 查找元素时是查找这个元素内满足的子元素


# 初始化谷歌驱动
driver = webdriver.Chrome()
# driver = webdriver.Edge()
# 等待页面加载完再查询元素，若页面元素未加载完就进行查询，有可能会报异常
# implicitly_wait(num) 方法是周期性重新寻找该元素，直到元素找到，超出最大等待时长num秒后还未找到该元素 就抛异常
# 后续webdriver对象调用fine_element() 或 fine_elements() 时都会自动的周期性查询元素
driver.implicitly_wait(10)  # 接收一个参数，指定等待的最大时长，若超出这个时长还未找到元素 就报异常

# 调用webdriver对象的get方法 ，让浏览器打开指定网页
driver.get("https://day-m.qxdaojia.com/")
# driver.get("https://www.baidu.com/")

# # 获取页面元素 通过id定位元素 返回的是该元素对应的webElement对象
# # 如果定位不到这个元素，会抛异常（NoSuchElementException） 可以使用try捕获异常
# element = driver.find_element(By.ID,'kw')   # 通过css中的id获取元素

# # element.send_keys("黑马\n")     # 设置关键字 类似于键盘输入 \n类似回车操作
# element.send_keys("百度")     # 没有回车 通过点击按钮进行搜索
#
# element = driver.find_element(By.ID,'su')
# element.click()   # 元素点击

# 获取页面元素 通过class定位元素 返回的是该元素对应的webElement对象
# find_elements()  查找满足的所有元素 返回的是列表 若查找不到元素则返回空列表
# elements = driver.find_elements(By.CLASS_NAME,'hot-refresh-text')
# print(elements[0].text)   # 获取元素内容
#
# # find_element()  查找满足的第一个元素 返回webElement对象 若找不到元素则会抛异常（NoSuchElementException）
# element = driver.find_element(By.CLASS_NAME,'title-content-title')
# print(element.text)
#
# # 获取页面元素 通过元素标签tag定位元素
# elements = driver.find_elements(By.TAG_NAME,'span')
# for e in elements:
#     print(e.text)


# 以上是通过整个网页去查询元素 以下是通过元素内部查找元素
element = driver.find_element(By.CLASS_NAME, 's-hotsearch-content')
spans = element.find_elements(By.TAG_NAME, 'span')
for s in spans:
    print(s.text)

# driver.quit()     # 结束进程 关闭浏览器打开的窗口

pass
print("******")

# --------------------------------------
# -----------操作元素
# 1 点击 element.click()
# 2 输入 element.send_keys("")
# 3 清空元素内容 element.clear()

# ------------获取元素信息
# element.text ：获取元素展示在页面上的文本内容
# element.get_attribute("innerText")
# element.get_attribute("textContent")

# ------------------------------------
# 获取元素属性
# element.get_attribute("属性")
# 获取元素的整个html
# element.get_attribute("outerHTML")
# 获取元素的内部的html
# element.get_attribute("innerHTML")
# 获取输入框的内容
# element.get_attribute("value")

# ---------------------------
# 通过css元素选择器定位元素
# element.find_element(By.CSS_SELECTOR,'')

# class： .class名
# id : #id名
# 其他属性选择： [属性名]
# 其他属性选择： [属性名 = "value"]
# 属性值包含yyy值:   [属性名 *= 'yyy']
# 属性值以xx开头:    [属性名 ^= 'xx']
# 属性值以zz结尾:    [属性名 $= 'zz']
# 查找子元素写法： 父元素>子元素
# 查找后代元素写法： 父元素 后代元素
# 按次序查找子节点，指定选择父节点下的第num个子节点元素：:nth-child(num)
# 按次序查找倒数字节点，指定选择父元素下的倒数第num个子节点元素： :nth-last-child(num)
# 按次序查找父节点下类型为xx的第num个子节点： :nth-of-type(num)
# 按次序查找父节点下类型为xx的倒数第num个子节点： :nth-last-of-type(num)
# 按次序查找父节点下的偶数子节点： :nth-child(even)
# 按次序查找父节点下的奇数子节点： :nth-child(odd)
# 按次序查找父节点下的类型为xx的偶数子节点： :nth-of-type(even)
# 按次序查找父节点下的类型为xx的奇数子节点： :nth-of-type(odd)
# 查找相邻兄弟节点： 元素1 + 元素2
# 查找所有兄弟节点： 元素1 ~ 元素2
# 查找多个元素: 逗号隔开

# 比如，查找id为div下的span，是父子节点的第2个元素： #div span:nth-child(2)
# 比如，查找class为div下span，是父节点的倒数第3个元素： .div>span:nth-last-child(3)
# 比如，查找id为div下的第4个元素，并且类型是span的： #div span:nth-of-type(4)
# 比如，查找id为div下的倒数第2个元素，并且类型是span的： #div span:nth-last-of-type(2)
# 比如，查找id为div下的偶数子节点： #div:nth-child(even)
# 比如，查找id为div下的奇数子节点： #div:nth-child(odd)
# 比如，查找id为div下的奇数子节点，且是span类型： #div span:nth-of-type(odd)
# 比如，查找id为div下的偶数子节点，且是span类型： #div span:nth-of-type(even)

# css选择框
# 元素的type属性值为"radio" 代表单选框
# 元素的type属性值为"checkbox" 代表多选框
# 元素的type属性值为"select" 代表菜单选择框,有单选和多选,多选多了multiple属性,selenium专门提供了Select类供操作

# --------------------selenium中的select类
# 导入Select类
from selenium.webdriver.support.ui import Select
# 创建Select对象
select = Select(driver.find_element(By.ID, 'select菜单选择框'))
select.select_by_value('菜单项的value值为xxx')     # 选中菜单选择框中value值为xxx的选项
select.select_by_index(2)     # 按照次序选中第个选项
select.select_by_visible_text("可见文本内容xx")     # 根据选项的可见文本内容为xx,选中该元素
select.deselect_all()     # 清除所有已选中的选项
select.deselect_by_index(3)    # 按照次序将第三个取消选中
select.deselect_by_value('value值为yyy')     # 取消选中value值为yyy的选项
select.deselect_by_visible_text('可见文本内容yy')     # 取消选中可见内容文本为yy的选项

# 除了常用的元素点击,输入以外,不常用的鼠标右键点击,双击,移动鼠标到某个元素,鼠标拖拽等操作selenium是提供ActionChains类实现的
# --------------------selenium中的ActionChains类
from selenium.webdriver.common.action_chains import ActionChains
ac = ActionChains(driver)    # webdriver对象作为参数传入
ac.move_to_element(       # 鼠标移动到某个元素上
    driver.find_element(By.ID, 'xxx')
).perform()


# 鼠标移入时看到内容,鼠标移开时内容消失,此时看不到隐藏的内容,就需要进行页面冻结
# ------冻结页面,5000ms = 5s
# 在开发者工具的console中输入: setTimeout(function(){debugger},5000)

# alert(警告信息):ok按钮
# confirm(确认信息):取消,确定
# prompt(提示输入框):取消,确定,输入框
# -------弹出对话框操作
# alert弹窗操作
driver.switch_to.alert.accept()    # 点击ok/确认按钮
alert_text = driver.switch_to.alert.text        # 获取对话框内的文本信息
# confirm弹窗操作
driver.switch_to.alert.accept()    # 点击确认按钮
driver.switch_to.alert.dismiss()   # 点击取消按钮
confirm_text = driver.switch_to.alert.text        # 获取对话框内的文本信息
# prompt弹窗操作
driver.switch_to.alert.accept()    # 点击确认按钮
driver.switch_to.alert.dismiss()   # 点击取消按钮
driver.switch_to.alert.send_keys("输入内容")   # 向输入框内输入内容
rompt_text = driver.switch_to.alert.text        # 获取对话框内的文本信息

# ------frame切换
# iframe元素和frame元素，在这两个元素内部可以嵌入另一份html文档数据
# 在使用selenium操作元素时，操作范围缺省是当前的html，不包含被嵌入在iframe元素或frame元素中的html内容
# 若要操作嵌入的html内容，可以通过以下方式访问嵌入的元素：
# driver.switch_to('frame元素的id属性值或name属性值')
# driver.switch_to(driver.find_element("定位frame元素"))    # 切换到frame元素内操作元素
# driver.switch_to.default_content()    # 切换到frame外部操作元素

# ---------窗口切换
# mainWindow_handle = driver.current_window_handle   # 存储当前窗口的handle
# 原本操作的是当前窗口的数据，需要切换到新窗口操作新窗口的元素时，可以通过以下算法判断是否切换到了新窗口
# for handle in driver.window_handles:
#     driver.switch_to.window(handle)    # 先切换到新窗口
#     if '窗口标题' in driver.title:    # 循环判断当前窗口是否为我们要操作的新窗口
#         break   # 如果是新窗口则跳出循环
# driver.switch_to.window(mainWindow_handle)    # 切换回之前的窗口，如果不知道之前窗口的hanle，则需要通过上面算法重新遍历一遍


# ------------xpath
# 使用 driver.find_element(By.XPATH, '元素路径') 定位元素信息
# 在xpath语法中,整个html文档根节点用/表示,类似文本路径进行元素选择,其中 / 像css中的 > ,表示直接子节点元素
# /html/body/div/span  : 这种就是元素的绝对路径,表示从当前节点向下寻找直接子级元素,也等于css中的 html>body>div>span
# //div//span/p :   这种就是元素的相对路径,表示从当前节点向下寻找所有的后代元素,也等于css中的 div span>p
# //div/span/*   : * 是通配符,表示任意节点的元素,也就是所有元素,也等于css中的 div span>*
# [@属性名 = '属性值']  : 是xpath中通过属性定位元素的写法,注意属性名前要有@,属性值要用单引号/双引号,如果属性有多个字,这里的属性值要写完整
# [contains(@属性名,'属性值')]   : 指属性包含某个属性值的元素,也等于css中 [属性名 *= '属性值']
# [starts-with(@属性名,'属性值')]   : 指属性以某个属性值的开头的元素,也等于css中 [属性名 ^= '属性值']
# [ends-with(@属性名,'属性值')]   : 指属性以某个属性值的结尾的元素,也等于css中 [属性名 $= '属性值']
# //div/span[@class = 'color']   : 也等于css中 div>span[.class名 = 'color']
# //div/*[num]  :   指div下的第num个子级元素,也等于css中 div>:nth-child(num)
# //div/span[num]  : 指类型为span的第num个元素,也等于css中 div>span:nth-of-type(num)
# //div/p[last()]   : 指div下倒数第一个类型的p的子级元素,也等于css中 div>p:nth-last-of-type(1)
# //div/p[last()-1]   : 指div下倒数第二个类型的p的子级元素,也等于css中 div>p:nth-last-of-type(2)
# /div/span[position() <= 2]   :选取类型为span的前面2个元素
# /div/span[position() < 4]   :选取类型为span的前面3个元素
# /div/span[position() > last()-2]   :选取类型为span的最后2个元素
# /div/span[position() >= last()-2]   :选取类型为span的最后3个元素
# 查找多个元素: 竖线隔开 | ,也等于css中的 逗号隔开
# 查找父节点:   css中没有的功能,使用 span/.. 表示查找span的父节点
# 查找后面的所有兄弟节点: span/following-sibling::*  表示向下查找span的所有兄弟节点元素
# 查找后面的指定兄弟节点: span/following-sibling::div  表示向下查找span的兄弟节点为div的元素
# 查找前面的所有兄弟节点: span/preceding-sibling::*  表示向上查找span的兄弟节点
# 查找前面的指定兄弟节点: span/following-sibling::div  表示向上查找span的兄弟节点为div的元素
# 查找元素内部的节点: 需以 ./ 开头,否则查询的是外部的元素节点
# ----------------简单练习
# from selenium import webdriver
# # 使用Chrome浏览器驱动
# driver = webdriver.Chrome()
# # 打开网页
# driver.get("https://www.baidu.com")
# # 定位搜索框并输入关键词
# search_box = driver.find_element_by_id("kw")
# search_box.send_keys("Python")
# # 点击搜索按钮
# search_button = driver.find_element_by_id("su")
# search_button.click()
# 关闭浏览器
# driver.quit()
